home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 4
/
Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso
/
Pearls
/
gfx
/
Viewer
/
CyberAnim
/
source.lha
/
CyberAnim.c
next >
Wrap
C/C++ Source or Header
|
1996-09-08
|
46KB
|
1,521 lines
/*****************************************************************************
Cybergraphics Animation Viewer v1.0 8 Sep 1996
-----------------------------------
The files in this archive may be distributed anywhere provided they are
unmodified and are not sold for profit.
Ownership and copyright of all files remains with the author:
Peter McGavin, 86 Totara Crescent, Lower Hutt, New Zealand.
e-mail: peterm@maths.grace.cri.nz
*****************************************************************************/
#include "CyberAnim.h" /* separate file for GST */
#include "unpack.h"
#include "math64.h"
#define WIDTH 320
#define HEIGHT 240
#define DEPTH 8
#define NBITMAPS 2
/****************************************************************************/
#ifdef __SASC
const char version[] = "$VER: CyberAnim 1.0 " __AMIGADATE__ ;
long __oslibversion = 38; /* we require at least OS3.0 */
char __stdiowin[] = "CON:20/50/500/130/CyberAnim";
char __stdiov37[] = "/AUTO/CLOSE";
#endif
#ifndef max
#define max(x,y) ((x)>=(y))?(x):(y)
#endif
char programname[20];
BPTR olddir = NULL;
struct RDArgs *rdargs = NULL;
/****************************************************************************/
#define ID_ANIM MAKE_ID('A','N','I','M')
#define ID_ILBM MAKE_ID('I','L','B','M')
#define ID_ANHD MAKE_ID('A','N','H','D')
#define ID_BMHD MAKE_ID('B','M','H','D')
#define ID_CMAP MAKE_ID('C','M','A','P')
#define ID_CAMG MAKE_ID('C','A','M','G')
#define ID_BODY MAKE_ID('B','O','D','Y')
#define ID_DLTA MAKE_ID('D','L','T','A')
/* Masking techniques */
#define mskNone 0
#define mskHasMask 1
#define mskHasTransparentColor 2
#define mskLasso 3
#define mskHasAlpha 4
/* Compression techniques */
#define cmpNone 0
#define cmpByteRun1 1
#define cmpByteRun2 2
/* Bitmap header (BMHD) structure */
struct BitMapHeader
{
UWORD bmh_Width; /* Width in pixels */
UWORD bmh_Height; /* Height in pixels */
WORD bmh_Left; /* Left position */
WORD bmh_Top; /* Top position */
UBYTE bmh_Depth; /* Number of planes */
UBYTE bmh_Masking; /* Masking type */
UBYTE bmh_Compression; /* Compression type */
UBYTE bmh_Pad;
UWORD bmh_Transparent; /* Transparent color */
UBYTE bmh_XAspect;
UBYTE bmh_YAspect;
WORD bmh_PageWidth;
WORD bmh_PageHeight;
};
/* Animation compression modes */
#define cmpDirect 0
#define cmpXor 1
#define cmpLongdelta 2
#define cmpShortdelta 3
#define cmpDelta 4
#define cmpBytedelta 5
#define cmpStereo 6
#define cmpAnim7 7
#define cmpJ 74
/* Animation header flags */
#define anfLongdata (1<<0)
#define anfXor (1<<1)
#define anfOnelist (1<<2)
#define anfRLC (1<<3)
#define anfVertical (1<<4)
#define anfLongoffsets (1<<5)
/* Animation header (ANHD) structure */
struct AnimHeader
{
UBYTE anh_Operation; /* Compression method */
UBYTE anh_Mask; /* plane mask (xor mode only) */
UWORD anh_W, anh_H; /* w & h of body (xor mode only) */
WORD anh_X, anh_Y; /* offset of body (xor mode only) */
ULONG anh_Abstime; /* 1/60s sec relative to 1st frame */
ULONG anh_Reltime; /* 1/60s sec relative to prev frame */
UBYTE anh_Interleave; /* Modify frame this many back (0=2) */
UBYTE anh_Pad0;
ULONG anh_Bits; /* animation header flags */
UBYTE anh_Pad[16];
};
struct mystream {
FILE *f;
UBYTE *rambuf;
UBYTE *rambufptr;
ULONG rambufsize;
};
struct options {
BOOL ram;
BOOL once;
BOOL dbuf;
BOOL warp;
BOOL modereq;
BOOL waittof;
};
/****************************************************************************/
struct Library *CyberGfxBase = NULL;
static struct Rectangle rect;
static struct TagItem ti[] =
{{SA_DisplayID, 0x40420000},
{SA_DClip, (ULONG)&rect},
{TAG_DONE, 0}};
static struct Screen *s = NULL;
static struct ExtNewScreen ns = {
0, 0, WIDTH, HEIGHT, DEPTH,
2, 1,
HIRES | LACE,
CUSTOMSCREEN | NS_EXTENDED,
NULL,
NULL,
NULL,
NULL,
&ti[0]
};
static struct Window *w = NULL;
static struct NewWindow nw = {
0,0, /* Starting corner */
WIDTH,HEIGHT, /* Width, height */
2,1, /* detail, block pens */
IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS, /* IDCMP flags */
WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_RMBTRAP, /* Window flags */
NULL, /* Pointer to first gadget */
NULL, /* Pointer to checkmark */
NULL, /* title */
NULL, /* screen pointer */
NULL, /* bitmap pointer */
0,0,0,0, /* window not sized */
CUSTOMSCREEN /* type of screen */
};
static struct BitMap *bm[NBITMAPS] = {NBITMAPS * NULL};
static BOOL using_fastmem_bitmap = FALSE;
static BOOL using_intermediate_buffer = FALSE;
static WORD *dirty = NULL;
static struct IFFHandle *iff = NULL;
static BOOL iff_is_open = FALSE;
static UWORD *emptypointer = NULL;
static struct FileRequester *fr = NULL;
static struct ScreenModeRequester *smr = NULL;
struct Library *TimerBase = NULL;
struct MsgPort *timermp = NULL;
struct timerequest *timerio = NULL;
ULONG timerclosed = TRUE;
struct EClockVal *time = NULL;
struct EClockVal *time0 = NULL;
struct EClockVal *time1 = NULL;
double micros_per_eclock; /* Length of EClock tick in microseconds */
/****************************************************************************/
static void partial_cleanup (void)
{
int i, plane;
if (iff_is_open) {
CloseIFF (iff);
iff_is_open = FALSE;
}
if (iff != NULL) {
if (iff->iff_Stream != NULL) {
if (((struct mystream *)iff->iff_Stream)->f != NULL)
fclose (((struct mystream *)iff->iff_Stream)->f);
if (((struct mystream *)iff->iff_Stream)->rambuf != NULL)
free (((struct mystream *)iff->iff_Stream)->rambuf);
free ((void *)iff->iff_Stream);
}
FreeIFF (iff);
iff = NULL;
}
for (i = 0; i < NBITMAPS; i++) {
if (!using_intermediate_buffer) {
if (bm[i] != NULL)
free (bm[i]);
} else if (using_fastmem_bitmap) {
if (bm[i] != NULL) {
for (plane = 0; plane < bm[i]->Depth; plane++)
if (bm[i]->Planes[plane] != NULL)
free (bm[i]->Planes[plane]);
free (bm[i]);
}
} else
FreeBitMap (bm[i]);
bm[i] = NULL;
}
if (dirty != NULL) {
free (dirty);
dirty = NULL;
}
if (w != NULL) {
CloseWindow (w);
w = NULL;
}
if (s != NULL) {
CloseScreen (s);
s = NULL;
}
if (emptypointer != NULL) {
FreeMem (emptypointer, 12);
emptypointer = NULL;
}
}
/****************************************************************************/
static void cleanup (void)
{
partial_cleanup ();
if (IFFParseBase != NULL) {
CloseLibrary ((struct Library *)IFFParseBase);
IFFParseBase = NULL;
}
if (olddir != NULL) {
CurrentDir (olddir);
olddir = NULL;
}
if (rdargs != NULL) {
FreeArgs (rdargs);
rdargs = NULL;
}
if (time1 != NULL) {
FreeMem (time1, sizeof(struct EClockVal));
time1 = NULL;
}
if (time0 != NULL) {
FreeMem (time0, sizeof(struct EClockVal));
time0 = NULL;
}
if (time != NULL) {
FreeMem (time, sizeof(struct EClockVal));
time = NULL;
}
if (!timerclosed) {
CloseDevice ((struct IORequest *)timerio);
timerclosed = TRUE;
TimerBase = NULL;
}
if (timerio != NULL) {
DeleteExtIO ((struct IORequest *)timerio);
timerio = NULL;
}
if (timermp != NULL) {
DeletePort (timermp);
timermp = NULL;
}
if (smr != NULL) {
FreeAslRequest (smr);
smr = NULL;
}
if (fr != NULL) {
FreeAslRequest (fr);
fr = NULL;
}
if (AslBase != NULL) {
CloseLibrary ((struct Library *)AslBase);
AslBase = NULL;
}
if (CyberGfxBase != NULL) {
CloseLibrary ((struct Library *)CyberGfxBase);
CyberGfxBase = NULL;
}
}
#ifdef __SASC
void _CXBRK (void)
{
cleanup ();
fprintf (stderr, "**Break\n");
exit (0);
}
#endif
/****************************************************************************/
static char bodystring[64];
static struct TextAttr topaz80 = {
"topaz.font", 8, 0, 0
};
static struct IntuiText bodytext[] = {
{0, 1, JAM2, 10, 8, &topaz80, programname, &bodytext[1]},
{0, 1, JAM2, 10, 20, &topaz80, bodystring, NULL},
};
static struct IntuiText negtext = {0, 1, JAM2, 6, 3, &topaz80, "Ok", NULL};
static void die (char *msg, ...)
/* Exit program with message, return code 10 */
{
va_list arglist;
cleanup ();
va_start (arglist, msg);
vsprintf (bodystring, msg, arglist);
va_end (arglist);
AutoRequest (w, &bodytext[0], NULL, &negtext, 0, 0, 320, 60);
exit (10);
}
/****************************************************************************/
static void *malloc_check (size_t size)
{
void *p;
if ((p = malloc (size)) == NULL)
die ("%s: Out of memory trying to allocate %ld bytes!", programname,
size);
return (p);
}
/****************************************************************************/
static void delay_until (struct EClockVal *next_time)
{
ReadEClock (time);
if (cmp64 (time, next_time) > 0) {
timerio->tr_node.io_Command = TR_ADDREQUEST;
*(struct EClockVal *)&timerio->tr_time = *next_time;
sub64 ((struct EClockVal *)&timerio->tr_time, time); /* timerio->tr_time -= time */
/* oldpri = SetTaskPri (thistask, 20); */ /* don't flicker when mouse moves */
DoIO ((struct IORequest *)timerio); /* delay */
/* SetTaskPri (thistask, oldpri); */ /* restore task priority */
}
while (cmp64 (time, next_time) > 0)
ReadEClock (time);
*next_time = *time;
}
/****************************************************************************/
static void parse_tooltypes (char *fname, struct options *opt)
{
struct DiskObject *obj;
char **toolarray;
if ((obj = GetDiskObject (fname)) != NULL) {
toolarray = obj->do_ToolTypes;
if (FindToolType (toolarray, "DISK") != NULL)
opt->ram = FALSE;
if (FindToolType (toolarray, "RAM") != NULL)
opt->ram = FALSE;
if (FindToolType (toolarray, "ONCE") != NULL)
opt->once = TRUE;
if (FindToolType (toolarray, "WARP") != NULL)
opt->warp = TRUE;
if (FindToolType (toolarray, "NOMODEREQ") != NULL)
opt->modereq = FALSE;
if (FindToolType (toolarray, "WAITTOF") != NULL)
opt->waittof = TRUE;
FreeDiskObject (obj);
}
}
/****************************************************************************/
static void load_cmap (struct Screen *s, UBYTE *cmap, int ncolours,
ULONG intended_mode)
{
int c;
ULONG *colourtable;
colourtable = (ULONG *)malloc_check ((1 + 3 * ncolours + 1) * sizeof(ULONG));
colourtable[0] = (ncolours << 16) + 0;
for (c = 0; c < ncolours; c++) {
colourtable[3 * c + 1] = *cmap++ * 0x01010101;
colourtable[3 * c + 2] = *cmap++ * 0x01010101;
colourtable[3 * c + 3] = *cmap++ * 0x01010101;
}
if ((intended_mode & EXTRAHALFBRITE_KEY) != 0) {
cmap -= 3 * ncolours;
for (c = ncolours >> 1; c < ncolours; c++) {
colourtable[3 * c + 1] = (cmap[0] >> 1) * 0x01010101;
colourtable[3 * c + 2] = (cmap[1] >> 1) * 0x01010101;
colourtable[3 * c + 3] = (cmap[2] >> 1) * 0x01010101;
cmap += 3;
}
}
colourtable[1 + 3 * ncolours] = 0;
LoadRGB32 (&s->ViewPort, colourtable);
free (colourtable);
}
/****************************************************************************/
static BOOL unpackrow (BYTE **src0, BYTE *dst, WORD dstbytes)
{
BYTE *src;
BYTE n;
BOOL err;
err = TRUE;
src = *src0;
while (dstbytes > 0) {
n = *src++;
if (n >= 0) {
n += 1;
if ((dstbytes -= n) < 0)
goto error;
memcpy (dst, src, n);
src += n;
} else if (n != -128) {
n = 1 - n;
if ((dstbytes -= n) < 0)
goto error;
memset (dst, *src++, n);
}
dst += n;
}
err = FALSE;
error:
*src0 = src;
return (err);
}
/****************************************************************************/
static void unpacklongdelta (WORD *wdata, LONG *plane, WORD bytesperrow,
WORD *dirty)
{
WORD offset, count;
while ((offset = *wdata++) != -1) {
if (offset >= 0) {
plane += offset;
*plane = *(LONG *)wdata;
wdata += 2;
} else {
count = *wdata++;
plane += -offset - 1;
memcpy (plane, wdata, count << 2);
plane += count - 1;
wdata += (count << 1);
}
}
}
/****************************************************************************/
static void unpackshortdelta (WORD *wdata, WORD *plane, WORD bytesperrow,
WORD *dirty)
{
WORD offset, count;
while ((offset = *wdata++) != -1) {
if (offset >= 0) {
plane += offset;
*plane = *wdata++;
} else {
/*
plane += -offset - 1;
for (count = *wdata++; count > 0; count--)
*plane++ = *wdata++;
plane--;
*/
count = *wdata++;
plane += -offset - 1;
memcpy (plane, wdata, count << 1);
plane += count - 1;
wdata += count;
}
}
}
/****************************************************************************/
#if 0
void __asm unpackbytedelta (register __a0 BYTE *bdata,
register __a1 PLANEPTR plane,
register __d0 WORD bytesperrow,
register __a2 WORD *dirty);
static void unpackbytedelta (BYTE *bdata, PLANEPTR plane, WORD bytesperrow,
WORD *dirty)
{
WORD x, y, count, w, first, last;
BYTE *bp;
UBYTE ub;
for (x = 0; x < bytesperrow; x++) {
first = -1;
last = -1;
bp = &plane[x];
y = 0;
for (count = *bdata++; count > 0; count--) {
if ((w = *bdata++) > 0) {
y += w;
bp += w * bytesperrow;
} else if (w < 0) {
if (first < 0)
first = y;
last = (y += (w &= 0x7f));
for ( ; w > 0; w--) {
*bp = *bdata++;
bp += bytesperrow;
}
} else /* w == 0 */ {
if (first < 0)
first = y;
last = (y += (ub = (UBYTE)*bdata++));
w = *bdata++;
for ( ; ub > 0; ub--) {
*bp = w;
bp += bytesperrow;
}
}
}
if (first >= 0 && (dirty[0] < 0 || first < dirty[0]))
dirty[0] = first;
if (last >= 0 && (dirty[1] < 0 || last > dirty[1]))
dirty[1] = last;
if ((x & 3) == 3)
dirty += 2;
}
}
#endif
/****************************************************************************/
static void unpackanim7word (BYTE *bdata, WORD *data, PLANEPTR plane,
WORD wordsperrow, WORD *dirty)
{
WORD x, y, count, w, first, last;
WORD *wp;
UBYTE ub;
for (x = 0; x < wordsperrow; x++) {
first = -1;
last = -1;
wp = &((WORD *)plane)[x];
y = 0;
for (count = *bdata++; count > 0; count--) {
if ((w = *bdata++) > 0) {
y += w;
wp += w * wordsperrow;
} else if (w < 0) {
if (first < 0)
first = y;
last = (y += (w &= 0x7f));
for ( ; w > 0; w--) {
*wp = *data++;
wp += wordsperrow;
}
} else /* w == 0 */ {
if (first < 0)
first = y;
last = (y += (ub = (UBYTE)*bdata++));
w = *data++;
for ( ; ub > 0; ub--) {
*wp = w;
wp += wordsperrow;
}
}
}
if (first >= 0 && (dirty[0] < 0 || first < dirty[0]))
dirty[0] = first;
if (last >= 0 && (dirty[1] < 0 || last > dirty[1]))
dirty[1] = last;
if ((x & 1) == 1)
dirty += 2;
}
}
/****************************************************************************/
#if 0
void __asm unpackanim7long (register __a0 BYTE *bdata,
register __a4 LONG *data,
register __a1 PLANEPTR plane,
register __d0 WORD bytesperrow,
register __a2 WORD *dirty);
static void unpackanim7long (BYTE *bdata, LONG *data, PLANEPTR plane,
WORD bytesperrow, WORD *dirty)
{
WORD x, y, count, w, first, last;
LONG *lp, l;
UBYTE ub;
for (x = 0; x < bytesperrow; x += 4) {
first = -1;
last = -1;
lp = &((LONG *)plane)[x];
y = 0;
for (count = *bdata++; count > 0; count--) {
if ((w = *bdata++) > 0) {
y += w;
lp += w * (bytesperrow >> 2);
} else if (w < 0) {
if (first < 0)
first = y;
last = (y += (w &= 0x7f));
for ( ; w > 0; w--) {
*lp = *data++;
lp += (bytesperrow >> 2);
}
} else /* w == 0 */ {
if (first < 0)
first = y;
last = (y += (ub = (UBYTE)*bdata++));
l = *data++;
for ( ; ub > 0; ub--) {
*lp = l;
lp += (bytesperrow >> 2);
}
}
}
if (first >= 0 && (dirty[0] < 0 || first < dirty[0]))
dirty[0] = first;
if (last >= 0 && (dirty[1] < 0 || last > dirty[1]))
dirty[1] = last;
dirty += 2;
}
}
#endif
/****************************************************************************/
static void blit_opt (struct BitMap *bm, struct RastPort *rp, WORD *dirty,
int yoffset)
{
WORD x, firstx, miny, maxy;
firstx = -1;
for (x = 0; x < bm->BytesPerRow; x += 4) {
if (dirty[0] >= 0 && dirty[1] >= 0) {
if (firstx == -1) {
firstx = x;
miny = dirty[0];
maxy = dirty[1];
} else if (abs(dirty[0] - miny) < 10 &&
abs(dirty[1] - maxy) < 10) {
miny = min(dirty[0], miny);
maxy = max(dirty[1], maxy);
} else {
BltBitMapRastPort (bm, firstx << 3, miny, rp, firstx << 3,
miny + yoffset, (x - firstx) << 3,
maxy - miny, 0xc0);
firstx = x;
miny = dirty[0];
maxy = dirty[1];
}
} else if (firstx != -1) {
BltBitMapRastPort (bm, firstx << 3, miny, rp, firstx << 3,
miny + yoffset, (x - firstx) << 3,
maxy - miny, 0xc0);
firstx = -1;
}
dirty += 2;
}
if (firstx != -1)
BltBitMapRastPort (bm, firstx << 3, miny, rp, firstx << 3,
miny + yoffset, (bm->BytesPerRow - firstx) << 3,
maxy - miny, 0xc0);
}
/****************************************************************************/
#if 0
static void PrintTopChunk (struct IFFHandle *iff)
{
struct ContextNode *top;
short i;
char idbuf[5];
/* Get a pointer to the context node describing the current context. */
if (!(top = CurrentChunk (iff)))
return;
/*
* Print a series of dots equivalent to the current nesting depth of chunks processed so far.
* This will cause nested chunks to be printed out indented.
*/
for (i = iff->iff_Depth; i--; )
printf (". ");
/* Print out the current chunk's ID and size. */
printf ("%s %ld ", IDtoStr (top->cn_ID, idbuf), top->cn_Size);
/* Print the current chunk's type, with a newline. */
puts (IDtoStr (top->cn_Type, idbuf));
}
#endif
/****************************************************************************/
#ifdef __SASC
static __saveds __asm LONG mystreamhandler (
register __a0 struct Hook *hook,
register __a2 struct IFFHandle *iff,
register __a1 struct IFFStreamCmd *actionpkt)
{
#else /* gcc */
static LONG mystreamhandler (void)
{
register struct Hook *hook __asm("a0");
register struct IFFHandle *iff __asm("a2");
register struct IFFStreamCmd *actionpkt __asm("a1");
#endif
struct mystream *s;
LONG nbytes, error;
UBYTE *buf;
s = (struct mystream *)iff->iff_Stream;
nbytes = actionpkt->sc_NBytes;
buf = (UBYTE *)actionpkt->sc_Buf;
switch (actionpkt->sc_Command) {
case IFFCMD_READ:
if (s->f != NULL)
error = (fread (buf, 1, nbytes, s->f) != nbytes);
else if (s->rambuf != NULL &&
nbytes <= s->rambuf + s->rambufsize - s->rambufptr &&
nbytes >= 0) {
/* printf ("Reading %d from %d\n", nbytes, s->rambufptr - s->rambuf); */
if (nbytes > 0) {
memcpy (buf, s->rambufptr, nbytes);
s->rambufptr += nbytes;
}
error = FALSE;
} else
error = TRUE;
break;
case IFFCMD_WRITE:
if (s->f != NULL)
error = (fwrite (buf, 1, nbytes, s->f) != nbytes);
else
error = TRUE;
break;
case IFFCMD_SEEK:
if (s->f != NULL)
error = (fseek (s->f, nbytes, SEEK_CUR) == -1);
else if (s->rambuf != NULL) {
s->rambufptr += nbytes;
error = s->rambufptr > (s->rambuf + s->rambufsize) ||
s->rambufptr < s->rambuf;
} else
error = TRUE;
break;
case IFFCMD_INIT:
case IFFCMD_CLEANUP:
error = FALSE;
break;
default:
error = TRUE;
}
return (error);
}
static struct Hook mystreamhook = {
{NULL},
(ULONG (*)())mystreamhandler,
NULL,
NULL
};
/****************************************************************************/
static void animate_file (char *fname, struct options opt)
{
int plane, /* x, */ y, i, width, height, oscan_height, depth, which, ifferror;
ULONG class, size, intended_mode, totalframes, sig;
UWORD code, count, propertymask, srcbytesperrow;
WORD *wdata;
UBYTE *body, *src, *dst[8], *dlta;
LONG fsize;
struct IntuiMessage *msg;
BOOL going, first_time;
struct StoredProperty *bmhdprop, *cmapprop, *camgprop, *anhdprop;
struct BitMapHeader *bmhd;
struct AnimHeader *anhd;
struct DimensionInfo dimsinfo;
struct mystream *mystream;
char reqtitle[30], *type_string;
struct EClockVal eclocks, warp_eclocks, total_eclocks, next_time;
parse_tooltypes (fname, &opt);
if ((iff = AllocIFF ()) == NULL)
die ("%s: AllocIFF() failed", programname);
mystream = (struct mystream *)malloc_check (sizeof(struct mystream));
memset (mystream, 0, sizeof(struct mystream));
if ((mystream->f = fopen (fname, "r")) == 0)
die ("%s: Can't open %s", programname, fname);
if (fseek (mystream->f, 0, SEEK_END) == -1 ||
(fsize = ftell (mystream->f)) == -1)
die ("%s: Error seeking %s", programname, fname);
rewind (mystream->f);
if (opt.ram && (mystream->rambuf = malloc (fsize)) != NULL) {
if (fread (mystream->rambuf, 1, fsize, mystream->f) != fsize ||
fclose (mystream->f) == EOF)
die ("%s: Error reading %s", programname, fname);
mystream->f = NULL;
mystream->rambufptr = mystream->rambuf;
mystream->rambufsize = fsize;
} else {
if (opt.ram)
printf ("Not enough memory to play from RAM, playing from DISK instead\n");
mystream->rambuf = NULL;
}
iff->iff_Stream = (ULONG)mystream;
InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &mystreamhook);
if (OpenIFF (iff, IFFF_READ) != 0)
die ("%s: OpenIFF() failed", programname);
iff_is_open = TRUE;
if (PropChunk (iff, ID_ILBM, ID_BMHD) != 0 ||
PropChunk (iff, ID_ILBM, ID_ANHD) != 0 ||
PropChunk (iff, ID_ILBM, ID_CMAP) != 0 ||
PropChunk (iff, ID_ILBM, ID_CAMG) != 0 ||
StopChunk (iff, ID_ILBM, ID_BODY) != 0)
die ("%s: Error calling PropChunk or StopChunk parsing %s", programname, fname);
if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0) {
fprintf (stderr, "%s: IFF error %d parsing %s\n", programname, ifferror, fname);
partial_cleanup ();
return;
}
if ((bmhdprop = FindProp (iff, ID_ILBM, ID_BMHD)) == NULL ||
(cmapprop = FindProp (iff, ID_ILBM, ID_CMAP)) == NULL) {
fprintf (stderr, "%s: Missing BMHD or CMAP parsing %s\n", programname, fname);
partial_cleanup ();
return;
}
bmhd = (struct BitMapHeader *)bmhdprop->sp_Data;
width = bmhd->bmh_Width;
height = bmhd->bmh_Height;
depth = bmhd->bmh_Depth;
if ((camgprop = FindProp (iff, ID_ILBM, ID_CAMG)) != NULL)
intended_mode = *(ULONG *)camgprop->sp_Data;
else
intended_mode = 0;
/* display file attributes */
printf ("\nFile = %s, size = %ld bytes\n", fname, fsize);
printf ("Anim size %ux%ux%u\n", width, height, depth);
printf ("Intended ModeID = %08lx", intended_mode);
type_string = "";
propertymask = DIPF_IS_EXTRAHALFBRITE | DIPF_IS_DUALPF | DIPF_IS_PF2PRI |
DIPF_IS_HAM;
if (camgprop != NULL &&
(*(ULONG *)camgprop->sp_Data & EXTRAHALFBRITE_KEY) != 0) {
printf (" (EXTRAHALFBRITE)");
type_string = " EHB";
propertymask &= ~DIPF_IS_EXTRAHALFBRITE;
}
if (camgprop != NULL &&
(*(ULONG *)camgprop->sp_Data & HAM_KEY) != 0) {
switch (depth) {
case 6:
printf (" (HAM)");
type_string = " HAM6";
break;
case 8:
printf (" (HAM8)");
type_string = " HAM8";
break;
default:
die ("%s: HAM but not depth 6 or 8", programname);
}
propertymask &= ~DIPF_IS_HAM;
}
printf ("\n");
first_time = TRUE;
warp_eclocks.ev_hi = 0;
warp_eclocks.ev_lo = 0;
eclocks.ev_hi = 0;
eclocks.ev_lo = 0;
total_eclocks.ev_hi = 0;
total_eclocks.ev_lo = 0;
if ((anhdprop = FindProp (iff, ID_ILBM, ID_ANHD)) != NULL) {
anhd = (struct AnimHeader *)anhdprop->sp_Data;
eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) * anhd->anh_Reltime /
micros_per_eclock + 0.5);
add64 (&total_eclocks, &eclocks);
}
if (CyberGfxBase != NULL)
ti[0].ti_Data = BestCModeIDTags (CYBRBIDTG_NominalWidth, max(width, 320),
CYBRBIDTG_NominalHeight, max(height, 200),
CYBRBIDTG_Depth, max(depth, 4),
TAG_DONE);
else if (GfxBase->LibNode.lib_Version >= 39)
ti[0].ti_Data = BestModeID (BIDTAG_NominalWidth, width,
BIDTAG_NominalHeight, height,
BIDTAG_Depth, depth,
BIDTAG_DIPFMustNotHave, propertymask,
TAG_DONE);
else
ti[0].ti_Data = 0;
if (opt.modereq) {
sprintf (reqtitle, "%s %dx%d%s", programname, width, height, type_string);
if (!AslRequestTags (smr,
ASLSM_TitleText, (ULONG)reqtitle,
ASLSM_InitialDisplayID, ti[0].ti_Data,
ASLSM_MinWidth, width,
ASLSM_MinHeight, height,
ASLSM_MinDepth, depth,
ASLSM_MaxDepth, 8,
ASLSM_PropertyMask, propertymask,
ASLSM_PropertyFlags, 0,
TAG_DONE))
die ("%s: ScreenMode requester failed or cancelled", programname);
ti[0].ti_Data = smr->sm_DisplayID;
}
printf ("Using ModeID = %08lx\n", ti[0].ti_Data);
if ((count = GetDisplayInfoData (NULL, (UBYTE *)&dimsinfo,
sizeof(struct DimensionInfo), DTAG_DIMS,
ti[0].ti_Data)) < 66
/* sizeof(struct DimensionInfo) */)
die ("%s: GetDisplayInfoData(Dims) failed (%d)", programname, count);
oscan_height = max(height, dimsinfo.MaxOScan.MaxY - dimsinfo.MaxOScan.MinY + 1);
ns.Width = width;
nw.Width = width;
ns.Height = oscan_height << 1;
nw.Height = oscan_height << 1;
ns.Depth = max (depth, 4);
rect.MaxX = width - 1;
rect.MaxY = height - 1;
if ((s = OpenScreen ((struct NewScreen *)&ns)) == NULL)
die ("%s: Can't open Screen", programname);
load_cmap (s, (UBYTE *)cmapprop->sp_Data, 1 << depth, intended_mode);
printf ("Screen size %ux%u\n", s->Width, s->Height >> 1);
nw.Screen = s;
if ((w = OpenWindow (&nw)) == NULL)
die ("%s: Can't open Window", programname);
emptypointer = (WORD *)AllocMem (12, MEMF_CHIP | MEMF_CLEAR);
SetPointer (w, emptypointer, 1, 16, 0, 0);
for (i = 0; i < NBITMAPS; i++) {
if (CyberGfxBase != NULL && IsCyberModeID (GetVPModeID (&s->ViewPort))) {
using_fastmem_bitmap = TRUE;
using_intermediate_buffer = TRUE;
bm[i] = malloc_check (sizeof(struct BitMap));
memset (bm[i], 0, sizeof(struct BitMap));
InitBitMap (bm[i], depth, width, height);
for (plane = 0; plane < bm[i]->Depth; plane++)
bm[i]->Planes[plane] = malloc_check (bm[i]->BytesPerRow * bm[i]->Rows);
} else if (GfxBase->LibNode.lib_Version >= 39 &&
(GetBitMapAttr (s->ViewPort.RasInfo->BitMap, BMA_FLAGS) &
BMF_STANDARD) != 0 &&
(GetBitMapAttr (s->ViewPort.RasInfo->BitMap, BMA_FLAGS) &
BMF_INTERLEAVED) == 0) {
using_fastmem_bitmap = FALSE;
using_intermediate_buffer = FALSE;
bm[i] = malloc_check (sizeof(struct BitMap));
memset (bm[i], 0, sizeof(struct BitMap));
bm[i]->Rows = height;
bm[i]->BytesPerRow = s->ViewPort.RasInfo->BitMap->BytesPerRow;
bm[i]->Depth = s->ViewPort.RasInfo->BitMap->Depth;
for (plane = 0; plane < bm[i]->Depth; plane++)
bm[i]->Planes[plane] = &s->ViewPort.RasInfo->BitMap->Planes[plane]
[i * bm[i]->BytesPerRow * oscan_height];
} else {
using_fastmem_bitmap = FALSE;
using_intermediate_buffer = TRUE;
if ((bm[i] = AllocBitMap (width, height, depth, 0, NULL)) == NULL)
die ("%s: Can't allocate bitmap", programname);
}
}
printf ("Bitmap size %ux%ux%u\n", bm[0]->BytesPerRow << 3,
bm[0]->Rows, bm[0]->Depth);
if (!using_fastmem_bitmap)
printf ("Using CHIPMEM\n");
if (!using_intermediate_buffer)
printf ("Using direct rendering\n");
dirty = (WORD *)malloc_check ((((bm[0]->BytesPerRow + 3) >> 2) << 1)
* sizeof(WORD));
/* PrintTopChunk (iff); */
size = CurrentChunk (iff)->cn_Size;
if (mystream->f != NULL) {
body = (UBYTE *)malloc_check (size);
if (ReadChunkBytes (iff, body, size) != size)
die ("%s: Error reading %s", programname, fname);
} else
body = mystream->rambufptr;
src = body;
srcbytesperrow = RASSIZE (width, 1);
for (plane = 0; plane < depth; plane++)
dst[plane] = bm[0]->Planes[plane];
for (y = 0; y < height; y++) {
for (plane = 0; plane < depth; plane++) {
switch (bmhd->bmh_Compression) {
case cmpNone:
memcpy (dst[plane], src, srcbytesperrow);
src += srcbytesperrow;
break;
case cmpByteRun1:
if (unpackrow ((BYTE **)&src, dst[plane], srcbytesperrow))
die ("%s: Error unpacking BODY", programname);
break;
default:
die ("%s: Unrecognised compression", programname);
}
dst[plane] += bm[0]->BytesPerRow;
}
}
if (mystream->f != NULL)
free (body);
for (plane = 0; plane < depth; plane++)
memcpy (bm[1]->Planes[plane], bm[0]->Planes[plane],
bm[0]->BytesPerRow * bm[0]->Rows);
if (using_intermediate_buffer) {
BltBitMapRastPort (bm[0], 0, 0, w->RPort, 0, 0, width, height, 0xc0);
BltBitMapRastPort (bm[1], 0, 0, w->RPort, 0, oscan_height, width, height,
0xc0);
}
/* read the start time */
ReadEClock (time0);
next_time = *time0;
add64 (&next_time, &eclocks);
which = 0;
totalframes = 1;
going = TRUE;
while (going) {
while ((msg = (struct IntuiMessage *)GetMsg (w->UserPort)) != NULL) {
class = msg->Class;
code = msg->Code;
ReplyMsg ((struct Message *)msg);
switch (class) {
case IDCMP_VANILLAKEY:
switch (code) {
case 0x03: /* CTRL/C */
case 0x1b: /* ESC */
case 0x51: /* q */
case 0x71: /* Q */
going = FALSE;
break;
default:
break;
}
break;
case IDCMP_RAWKEY:
switch (code) {
case 0x50: /* F1 */
warp_eclocks.ev_lo = 0;
opt.warp = TRUE;
break;
case 0x51: /* F2 */
warp_eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x52: /* F3 */
warp_eclocks.ev_lo = (ULONG)((1000000.0 / 30.0) / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x53: /* F4 */
warp_eclocks.ev_lo = (ULONG)((1000000.0 / 24.0) / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x54: /* F5 */
warp_eclocks.ev_lo = (ULONG)((1000000.0 / 15.0) / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x55: /* F6 */
warp_eclocks.ev_lo = (ULONG)((1000000.0 / 12.0) / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x56: /* F7 */
warp_eclocks.ev_lo = (ULONG)((1000000.0 / 10.0) / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x57: /* F8 */
warp_eclocks.ev_lo = (ULONG)((1000000.0 / 5.0) / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x58: /* F9 */
warp_eclocks.ev_lo = (ULONG)(1000000.0 / micros_per_eclock + 0.5);
opt.warp = TRUE;
break;
case 0x59: /* F10 */
opt.warp = FALSE;
break;
default:
break;
}
break;
case IDCMP_MOUSEBUTTONS:
if (code == MENUDOWN)
going = FALSE;
break;
default:
break;
}
}
#ifdef __SASC
chkabort ();
#endif
/* PrintTopChunk (iff); */
while ((ifferror = ParseIFF (iff, IFFPARSE_RAWSTEP)) == IFFERR_EOC)
/* do nothing */ ;
if (ifferror == IFFERR_EOF)
if (opt.once)
break;
else {
CloseIFF (iff);
iff_is_open = FALSE;
if (mystream->f != NULL)
rewind (mystream->f);
else if (mystream->rambuf != NULL)
mystream->rambufptr = mystream->rambuf;
else
die ("%s: Internal error", programname);
if (OpenIFF (iff, IFFF_READ) != 0)
die ("%s: OpenIFF() failed", programname);
iff_is_open = TRUE;
if (StopChunk (iff, ID_ILBM, ID_BODY) != 0)
die ("%s: Error calling StopChunk parsing %s", programname, fname);
if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0)
die ("%s: IFF error %d parsing %s for BODY", programname, ifferror, fname);
while ((ifferror = ParseIFF (iff, IFFPARSE_RAWSTEP)) == IFFERR_EOC)
/* do nothing */ ;
if (StopChunk (iff, ID_ILBM, ID_DLTA) != 0)
die ("%s: Error calling StopChunk parsing %s", programname, fname);
if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0)
if (ifferror != IFFERR_EOF)
die ("%s: IFF error %d parsing %s for DLTA", programname, ifferror, fname);
else {
while (going) {
sig = Wait ((1 << w->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C);
if ((sig & (1 << w->UserPort->mp_SigBit)) != 0) {
while ((msg = (struct IntuiMessage *)GetMsg (w->UserPort)) != NULL) {
class = msg->Class;
code = msg->Code;
ReplyMsg ((struct Message *)msg);
switch (class) {
case IDCMP_VANILLAKEY:
switch (code) {
case 0x03: /* CTRL/C */
case 0x1b: /* ESC */
case 0x51: /* q */
case 0x71: /* Q */
going = FALSE;
break;
default:
break;
}
break;
case IDCMP_MOUSEBUTTONS:
if (code == MENUDOWN)
going = FALSE;
break;
default:
break;
}
}
}
if ((sig & SIGBREAKF_CTRL_C) != 0)
going = FALSE;
}
}
continue;
}
else if (ifferror != 0)
die ("%s: IFF error %d parsing %s", programname, ifferror, fname);
which = 1 - which;
/* PrintTopChunk (iff); */
if (PropChunk (iff, ID_ILBM, ID_ANHD) != 0 ||
PropChunk (iff, ID_ILBM, ID_CMAP) != 0 ||
StopChunk (iff, ID_ILBM, ID_DLTA) != 0)
die ("%s: Error calling PropChunk or StopChunk parsing %s", programname, fname);
if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0)
die ("%s: IFF error %d parsing %s", programname, ifferror, fname);
if ((anhdprop = FindProp (iff, ID_ILBM, ID_ANHD)) == NULL)
die ("%s: missing ANHD chunk parsing %s", programname, fname);
anhd = (struct AnimHeader *)anhdprop->sp_Data;
eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) * anhd->anh_Reltime /
micros_per_eclock + 0.5);
add64 (&total_eclocks, &eclocks);
if (first_time) {
printf ("Anim type %d, abstime %ld, reltime, %ld, interleave %d, flags %08x\n",
(int)anhd->anh_Operation, anhd->anh_Abstime, anhd->anh_Reltime,
(int)anhd->anh_Interleave, anhd->anh_Bits);
first_time = FALSE;
}
size = CurrentChunk (iff)->cn_Size;
/* printf ("DLTA size %d at %d\n", size, CurrentChunk (iff)->cn_Scan); */
if (mystream->f != NULL) {
dlta = malloc_check (size);
if (ReadChunkBytes (iff, dlta, size) != size)
die ("%s: Error reading %s", programname, fname);
} else
dlta = mystream->rambufptr;
if (using_intermediate_buffer)
memset (dirty, -1, (((bm[0]->BytesPerRow + 3) >> 2) << 1) * sizeof(WORD));
else
if (opt.waittof)
WaitTOF ();
for (plane = 0; plane < depth; plane++) {
wdata = (WORD *)&dlta[((ULONG *)dlta)[plane]];
/* printf ("%d %08x %ld\n", plane, wdata, ((ULONG *)dlta)[plane]); */
switch (anhd->anh_Operation) {
case cmpLongdelta: /* 2 */
if (wdata != (WORD *)dlta)
unpacklongdelta (wdata, (LONG *)bm[which]->Planes[plane],
bm[which]->BytesPerRow, dirty);
break;
case cmpShortdelta: /* 3 */
if (wdata != (WORD *)dlta)
unpackshortdelta (wdata, (WORD *)bm[which]->Planes[plane],
bm[which]->BytesPerRow, dirty);
break;
case cmpBytedelta: /* 5 */
if (wdata != (WORD *)dlta)
if (using_intermediate_buffer)
unpackbytedelta ((BYTE *)wdata, bm[which]->Planes[plane],
bm[which]->BytesPerRow, dirty);
else
unpackbytedeltanodirty ((BYTE *)wdata, bm[which]->Planes[plane],
bm[which]->BytesPerRow);
break;
case cmpAnim7: /* 7 */
if (wdata != (WORD *)dlta)
if ((anhd->anh_Bits & 1) != 0)
if (using_intermediate_buffer)
unpackanim7long ((BYTE *)wdata,
(LONG *)&dlta[((ULONG *)dlta)[plane + 8]],
bm[which]->Planes[plane],
bm[which]->BytesPerRow,
dirty);
else
unpackanim7longnodirty ((BYTE *)wdata,
(LONG *)&dlta[((ULONG *)dlta)[plane + 8]],
bm[which]->Planes[plane],
bm[which]->BytesPerRow);
else
unpackanim7word ((BYTE *)wdata,
(WORD *)&dlta[((ULONG *)dlta)[plane + 8]],
bm[which]->Planes[plane],
bm[which]->BytesPerRow >> 1,
dirty);
break;
case cmpDirect: /* 0 */
case cmpXor: /* 1 */
case cmpDelta: /* 4 */
case cmpStereo: /* 6 */
case cmpJ: /* 74 */
default:
die ("%s: Anim type %d not recognised", programname,
(int)anhd->anh_Operation);
}
}
if (mystream->f != NULL)
free (dlta);
if (using_intermediate_buffer) {
/* need to wait for cybergraphics TOF to avoid flicker here, but HOW????
WaitTOF() appears to wait for custom chips which are different
frequency and phase to cybergraphics display. */
if (opt.waittof)
WaitTOF ();
if (anhd->anh_Operation == cmpBytedelta ||
anhd->anh_Operation == cmpAnim7)
blit_opt (bm[which], w->RPort, dirty, which != 0 ? oscan_height : 0);
else
BltBitMapRastPort (bm[which], 0, 0, w->RPort, 0,
which != 0 ? oscan_height : 0, width, height, 0xc0);
}
/* wait for time between frames */
delay_until (&next_time);
if (opt.warp)
add64 (&next_time, &warp_eclocks);
else
add64 (&next_time, &eclocks);
if ((cmapprop = FindProp (iff, ID_ILBM, ID_CMAP)) != NULL)
load_cmap (s, (UBYTE *)cmapprop->sp_Data, 1 << depth, intended_mode);
/* MoveScreen (s, which != 0 ? oscan_height : -oscan_height, 0); */
if (which != 0)
s->ViewPort.RasInfo->RyOffset += oscan_height;
else
s->ViewPort.RasInfo->RyOffset -= oscan_height;
ScrollVPort (&s->ViewPort);
totalframes++;
}
/* find out and display how long it took */
ReadEClock (time1);
if (total_eclocks.ev_hi != 0 || total_eclocks.ev_lo != 0)
printf ("%s: Intended frames per second = %4.1lf\n", programname,
1000000.0 * totalframes /
((total_eclocks.ev_hi * 4294967296.0 + total_eclocks.ev_lo) *
micros_per_eclock));
sub64 (time1, time0);
printf ("%s: Achieved frames per second = %4.1lf\n", programname,
1000000.0 * totalframes /
((time1->ev_hi * 4294967296.0 + time1->ev_lo) * micros_per_eclock));
partial_cleanup ();
}
/****************************************************************************/
static void filerequestloop (struct options *opt)
{
static char resultstring[128];
if (AslBase != NULL) {
while (AslRequest (fr, NULL)) {
strcpy (resultstring, fr->rf_Dir);
AddPart (resultstring, fr->rf_File, 128);
animate_file (resultstring, *opt);
}
}
}
/****************************************************************************/
static LONG argarray[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int main (int argc, char *argv[])
{
struct WBStartup *argmsg;
struct WBArg *wb_arg;
char **fnames;
UWORD ktr;
struct options opt;
if (atexit (cleanup) != 0)
die ("Can't install exit handler");
GetProgramName (programname, 19);
CyberGfxBase = OpenLibrary ("cybergraphics.library", 0);
if ((IFFParseBase = OpenLibrary ("iffparse.library", 0)) == NULL)
die ("%s: Can't open iff.library", programname);
if ((AslBase = (struct Library *)OpenLibrary ("asl.library", 38L)) == NULL)
die ("%s: Can't open asl.library v38", programname);
if ((fr = (struct FileRequester *)AllocAslRequestTags (ASL_FileRequest,
ASL_Hail, (ULONG)programname,
ASL_Pattern, (ULONG)"~(#?.info)",
ASL_OKText, (ULONG)"Play",
ASL_CancelText, (ULONG)"Cancel",
ASL_FuncFlags, FILF_PATGAD,
TAG_DONE)) == NULL)
die ("%s: Can't allocate file requester\n", programname);
if ((smr = AllocAslRequestTags (ASL_ScreenModeRequest, TAG_DONE)) == NULL)
die ("%s: Can't allocate screenmode requester\n", programname);
/* timer stuff */
if ((timermp = CreatePort (0, 0)) == NULL)
die ("%s: Can't create messageport!", programname);
if ((timerio = (struct timerequest *)CreateExtIO (timermp,
sizeof(struct timerequest))) == NULL)
die ("%s: Can't create External IO!", programname);
if (timerclosed = OpenDevice (TIMERNAME, UNIT_MICROHZ,
(struct IORequest *)timerio, 0))
die ("%s: Can't open timer.device!", programname);
TimerBase = (struct Library *)timerio->tr_node.io_Device;
if ((time = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
MEMF_CLEAR | MEMF_PUBLIC)) == NULL ||
(time0 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
MEMF_CLEAR | MEMF_PUBLIC)) == NULL ||
(time1 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
die ("%s: Out of memory", programname);
micros_per_eclock = 1000000.0 / (double)ReadEClock (time);
opt.ram = TRUE;
opt.once = FALSE;
opt.dbuf = TRUE;
opt.warp = FALSE;
opt.modereq = TRUE;
opt.waittof = FALSE;
/* parse workbench message or commandline */
if (argc == 0) {
argmsg = (struct WBStartup *)argv;
wb_arg = argmsg->sm_ArgList;
strcpy (programname, wb_arg->wa_Name);
parse_tooltypes (wb_arg->wa_Name, &opt);
if (argmsg->sm_NumArgs <= 1)
filerequestloop (&opt);
else {
wb_arg++;
for (ktr = 1; ktr < argmsg->sm_NumArgs; ktr++, wb_arg++)
if (wb_arg->wa_Lock != NULL) {
olddir = CurrentDir (wb_arg->wa_Lock);
animate_file (wb_arg->wa_Name, opt);
CurrentDir (olddir);
olddir = NULL;
} else
animate_file (wb_arg->wa_Name, opt);
}
} else {
if ((rdargs = ReadArgs
("FILE/M,DISK/S,RAM/S,ONCE/S,WARP/S,NOMODEREQ/S,WAITTOF/S", argarray,
NULL)) != NULL) {
if (argarray[1])
opt.ram = FALSE;
if (argarray[2])
opt.ram = TRUE;
if (argarray[3])
opt.once = TRUE;
if (argarray[4])
opt.warp = TRUE;
if (argarray[5])
opt.modereq = FALSE;
if (argarray[6])
opt.waittof = TRUE;
fnames = (char **)argarray[0];
if (fnames == NULL || *fnames == NULL)
filerequestloop (&opt);
else
while (*fnames != NULL)
animate_file (*fnames++, opt);
FreeArgs (rdargs);
rdargs = NULL;
}
}
return (0);
}
/****************************************************************************/